//
// File: database.cpp
// Description: 
//

#include "database.h"

Database *Database::instance = 0;

//
//
Database *Database::getInstance() {
	if (instance == 0)
		instance = new Database();
	
	return instance;
}

Database & Database::get() {
	if (instance == 0)
		instance = new Database();
	
	return *instance;
}


//
//
Database::Database() {
	conn.open(DBNAME);
	if (validate()) {
		cout << "Database verified ["DBNAME"]" << endl;
	} else {
		cout << "Database is invalid, constructing..." << endl;
		construct();
	}
	
	// prepare the statements
	cmd_insertUser = "insert into users (name, password) values(?,?);";
	cmd_login = "select count(*) from users where name = ? and password = ?;";
	cmd_userExists = "select count(*) from users where name = ?;";
}

//
//
Database::~Database() {
	conn.close();
}

//
//
bool Database::validate() {
	// check for user table
	int c = conn.executeint(
		"select count(*) from sqlite_master where name = 'users'");
	
	return c > 0;
}

//
//
bool Database::construct() {
	ostringstream user_table;
	user_table << "CREATE TABLE [users] (" <<
		"[uid] INTEGER PRIMARY KEY NOT NULL," <<
		"[name] VARCHAR(255) NULL," << 
		"[password] VARCHAR(255) NULL" <<
		")";
	
	try {
		conn.executenonquery(user_table.str());
	} catch (exception &ex) {
		cerr << "construct: " << ex.what() << endl;
		exit(1);
	}
	
}


//
//
bool Database::usernameExists(const string username) {
	ostringstream q;
	q << "select count(*) from users where name = '" << escape(username) << "'";
	
	int c = 0;
	try {
		sqlite3_command cmd(conn, cmd_userExists);
		cmd.bind(1, username);
		c = cmd.executeint();
	} catch (exception &ex) {
		cerr << "usernameExists: " << ex.what() << endl;
		exit(1);
	}
	return c > 0;
}

//
//
bool Database::login(const string username, const string password) {
	
	int c = 0;
	try {
		sqlite3_command cmd(conn, cmd_login);
		cmd.bind(1, username);
		cmd.bind(2, password);
		c = cmd.executeint();
	} catch (exception &ex) {
		cerr << "login: " << ex.what() << endl;
		exit(1);
	}
	
	return c > 0;
}

//
//
bool Database::createUser(const string username, const string password) {
	if (usernameExists(username)) return false;
	try {
		sqlite3_command cmd(conn, cmd_insertUser);
		cmd.bind(1, username);
		cmd.bind(2, password);
		cmd.executenonquery();
	} catch (exception &ex) {
		cerr << "createUser: " << ex.what() << endl;
		exit(1);
	}
	
	return true;
}

//
//
string Database::escape(const string str) {
	// count number of '
	int count = 0;
	const char* cstr = str.c_str();
	for (int c = 0; c < str.length(); c++) {
		if (cstr[c] == '\'') count++;
	}
	
	char buffer[str.length() + count + 1];
	// write new string
	int i = 0;
	for (int c = 0; c < str.length(); c++) {
		buffer[i] = cstr[c];
		if (cstr[c] == '\'') {
			i++;
			buffer[i] = cstr[c];
		}
		i++;
	}
	buffer[i] = '\0';
	
	return string(buffer);
}

